package com.mcp_life.common.config;

import com.mcp_life.common.context.SystemConstants;
import com.mcp_life.module.mcpclientmodules.model.AlibabaOpenAiChatModel;
import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.autoconfigure.openai.OpenAiChatProperties;
import org.springframework.ai.autoconfigure.openai.OpenAiConnectionProperties;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;

import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.model.SimpleApiKey;
import org.springframework.ai.model.tool.ToolCallingManager;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiEmbeddingModel;
import org.springframework.ai.openai.api.OpenAiApi;

import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClient;
import org.springframework.web.reactive.function.client.WebClient;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Configuration
public class CommonConfiguration {
    @Bean
    public ChatMemory chatMemory() {
        return new InMemoryChatMemory();
    }

    /**
     * AI问答客户端，本地部署单模态版本
     * @param model
     * @param chatMemory
     * @return
     */
//    @Bean
//    public ChatClient chatClient(OllamaChatModel model , ChatMemory chatMemory) {
//        return ChatClient.builder(model)
//                .defaultSystem("你是一个热心可爱的智能助手，叫做小K，请以小K的口吻回答问题。")
//                .defaultAdvisors(new SimpleLoggerAdvisor(),
//                                 new MessageChatMemoryAdvisor(chatMemory))//配置日志,记忆
//                .build();
//    }

    /**
     * AI问答客户端，多模态版本
     * @param model
     * @param chatMemory
     * @return
     */
//    @Bean
//    public ChatClient chatClient(OpenAiChatModel model , ChatMemory chatMemory) {
//        return ChatClient.builder(model)
//                .defaultOptions(ChatOptions.builder().model("qwen-omni-turbo").build())
//                .defaultSystem("你是一个活泼可爱的智能助手，叫做小K，请以小K的口吻回答的问题。")
//                .defaultAdvisors(
//                        new SimpleLoggerAdvisor(),
//                        new MessageChatMemoryAdvisor(chatMemory))//配置日志,记忆
//                .build();
//    }

    /**
     * 已解决阿里巴巴兼容性
     * @param model
     * @param chatMemory
     * @return
     */
//    @Bean
//    @Primary
//    public ChatClient chatClient(AlibabaOpenAiChatModel model, ChatMemory chatMemory) {
//        return ChatClient.builder(model) // 创建ChatClient工厂实例
//                .defaultOptions(ChatOptions.builder().model("qwen-omni-turbo").build())
//                .defaultSystem("你是一个热心可爱的小助手，叫做小K。请以友好、乐于助人和愉快的方式解答用户的各种问题。")
//                .defaultAdvisors(new SimpleLoggerAdvisor()) // 添加默认的Advisor,记录日志
//                .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory))
//                .build(); // 构建ChatClient实例
//
//    }
        @Bean
    public ChatClient MCPchatClient(ChatClient.Builder builder, ToolCallbackProvider tools){
        return builder.defaultSystem("""
                你是一个AI助手，请分析用户的问题，做出不同的处理，你现在拥有以下能力
                1.如果用户的提问包含城市和天气，就为用户查询指定城市的天气
                2.如果用户的提问包含商品，就为用户查询商品信息
                3.如果用户的提问是关于日期的，就为用户查询查询历史上所有今天发生的事
                4.如果用户的提问是关于今日热点的，就为用户查询热点新闻,同时如果用户指定了查询的数量（num）就按数量去查询，如果用户未指定num，就默认num=6去查询
                """).defaultTools(tools).build();
    }

    /**
     * 女友模拟器客户端
     * @param model
     * @param chatMemory
     * @return
     */
    @Bean
    public ChatClient gamechatClient(OpenAiChatModel model,ChatMemory chatMemory) {
        return ChatClient.builder(model)
                .defaultSystem(SystemConstants.GAME_SYSTEM_PROMPT)
                .defaultAdvisors(new SimpleLoggerAdvisor(),
                        new MessageChatMemoryAdvisor(chatMemory))//配置日志,记忆
                .build();
    }

    /**
     * AI客服客户端
     * @param model
     * @param chatMemory
     * @param courseTools
     * @return
     */
//    @Bean
//    //TODO: 未处理阿里巴巴的ai与openAI的流式响应不兼容问题，这里暂时使用阻塞式输出。
//    public ChatClient servicechatClient(OpenAiChatModel model, ChatMemory chatMemory, CourseTools courseTools) {
//        return ChatClient.builder(model)
//                .defaultSystem(SystemConstants.AI_HELP_SYSTEM_PROMPT)
//                .defaultAdvisors(new SimpleLoggerAdvisor(),
//                        new MessageChatMemoryAdvisor(chatMemory))//配置日志,记忆
//                .defaultTools(courseTools)
//                .build();
//    }

    /**
     * 兼容性问题解决
     * @param model
     * @param chatMemory
     * @param courseTools
     * @return
     */
//    @Bean
//    public ChatClient servicechatClient(
//            AlibabaOpenAiChatModel model,
//            ChatMemory chatMemory,
//            CourseTools courseTools) {
//        return ChatClient.builder(model)
//                .defaultSystem(SystemConstants.AI_HELP_SYSTEM_PROMPT)
//                .defaultAdvisors(
//                        new MessageChatMemoryAdvisor(chatMemory), // CHAT MEMORY
//                        new SimpleLoggerAdvisor())
//                .defaultTools(courseTools)
//                .build();
//    }
//    @Bean
//    public ChatClient pdfchatClient(OpenAiChatModel model, ChatMemory chatMemory,VectorStore vectorStore) {
//        return ChatClient.builder(model)
//                .defaultSystem("读取用户上传的pdf文件之后，根据文件内容回答")
//                .defaultAdvisors(
//                        new MessageChatMemoryAdvisor(chatMemory),
//                        new SimpleLoggerAdvisor(),
//                        new QuestionAnswerAdvisor(
//                                vectorStore,//传递向量库，自动检索！
//                                SearchRequest.builder()//向量检索请求参数
//                                        .similarityThreshold(0.6d)//最低相关度
//                                        .topK(3)//返回3个最相关的信息
//                                        .build()
//                        )
//                )
//                .build();
//    }

    /**
     * 配置本地向量数据库
     * @param openAiEmbeddingModel
     * @return
     */
    @Bean
    public VectorStore vectorStore(OpenAiEmbeddingModel openAiEmbeddingModel) {
        return SimpleVectorStore.builder(openAiEmbeddingModel).build();
    }
    //TODO ： 阿里巴巴平台兼容性问题。未解决，目前仍使用原生阿里巴巴openai接口
    @Bean
    @Primary
    public AlibabaOpenAiChatModel alibabaOpenAiChatModel(OpenAiConnectionProperties commonProperties, OpenAiChatProperties chatProperties, ObjectProvider<RestClient.Builder> restClientBuilderProvider, ObjectProvider<WebClient.Builder> webClientBuilderProvider, ToolCallingManager toolCallingManager, RetryTemplate retryTemplate, ResponseErrorHandler responseErrorHandler, ObjectProvider<ObservationRegistry> observationRegistry, ObjectProvider<ChatModelObservationConvention> observationConvention) {
        String baseUrl = StringUtils.hasText(chatProperties.getBaseUrl()) ? chatProperties.getBaseUrl() : commonProperties.getBaseUrl();
        String apiKey = StringUtils.hasText(chatProperties.getApiKey()) ? chatProperties.getApiKey() : commonProperties.getApiKey();
        String projectId = StringUtils.hasText(chatProperties.getProjectId()) ? chatProperties.getProjectId() : commonProperties.getProjectId();
        String organizationId = StringUtils.hasText(chatProperties.getOrganizationId()) ? chatProperties.getOrganizationId() : commonProperties.getOrganizationId();
        Map<String, List<String>> connectionHeaders = new HashMap<>();
        if (StringUtils.hasText(projectId)) {
            connectionHeaders.put("OpenAI-Project", List.of(projectId));
        }

        if (StringUtils.hasText(organizationId)) {
            connectionHeaders.put("OpenAI-Organization", List.of(organizationId));
        }
        RestClient.Builder restClientBuilder = restClientBuilderProvider.getIfAvailable(RestClient::builder);
        WebClient.Builder webClientBuilder = webClientBuilderProvider.getIfAvailable(WebClient::builder);
        OpenAiApi openAiApi = OpenAiApi.builder().baseUrl(baseUrl).apiKey(new SimpleApiKey(apiKey)).headers(CollectionUtils.toMultiValueMap(connectionHeaders)).completionsPath(chatProperties.getCompletionsPath()).embeddingsPath("/v1/embeddings").restClientBuilder(restClientBuilder).webClientBuilder(webClientBuilder).responseErrorHandler(responseErrorHandler).build();
        AlibabaOpenAiChatModel chatModel = AlibabaOpenAiChatModel.builder().openAiApi(openAiApi).defaultOptions(chatProperties.getOptions()).toolCallingManager(toolCallingManager).retryTemplate(retryTemplate).observationRegistry((ObservationRegistry)observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)).build();
        Objects.requireNonNull(chatModel);
        observationConvention.ifAvailable(chatModel::setObservationConvention);
        return chatModel;
    }


}
